package com.ccx.demo.config;
//
//import com.alibaba.fastjson.JSON;
//import com.alibaba.fastjson.TypeReference;
//import com.ccx.demo.config.init.AppConfig;
//import com.support.config.AbstractMvcConfig;
//import com.utils.util.Dates;
//import com.utils.util.Range;
//import com.utils.util.RangeInt;
//import com.utils.util.RangeLong;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.core.convert.converter.Converter;
//import org.springframework.format.FormatterRegistry;
//import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
//
//import java.math.BigDecimal;
//import java.sql.Timestamp;
//import java.util.Date;
//import java.util.List;
//
//import static com.utils.util.Dates.Pattern.yyyy_MM_dd_HH_mm_ss_SSS;
//
///**
// * <pre>
// * Spring Core，参考：
// * https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
// *
// * Spring MVC 配置，参考 ：
// * https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/
// * https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html
// *
// * Spring Thymeleaf 配置，参考 ：
// * https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#spring-mvc-configuration
// *
// * Spring validator 配置，参考
// * https://beanvalidation.org/2.0/spec/#introduction
// * https://www.baeldung.com/javax-validation-method-constraints
// * http://rubygems.torquebox.org/proposals/BVAL-241/
// * https://juejin.im/entry/5b5a94d2f265da0f7c4fd2b2
// * https://www.cnblogs.com/mr-yang-localhost/p/7812038.html
// *
// * @author 谢长春 2018-10-3
// */
//@Slf4j
//@Configuration
//@RequiredArgsConstructor
//public class WebMvcConfig extends AbstractMvcConfig {
//
//    private final AppConfig appConfig;
//
//    /**
//     * 添加自定义拦截器
//     */
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        // 没有使用 security 时，可以使用拦截器拦截请求，设置链路追踪
////        registry.addInterceptor(new RequestIdInterceptor()).addPathPatterns("/**");
//    }
//
//    @Override
//    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
//        super.addResourceHandlers(registry);
//        // 添加静态资源过滤
//        // 需要在 Spring Security 中配置忽略静态资源 WebSecurity.ignoring().antMatchers("/files/**");
//        registry.addResourceHandler(String.format("/%s/**", appConfig.getName()))
//                // TODO 采坑记录结尾带 / 和不带 / 的区别
//                //   假设请求url为：http://{{host}}:{{port}}/files/temp/a.txt
//                //   addResourceLocations 指定绝对路径
//                //   d:/files => d:/temp/a.txt
//                //   d:/files/ => d:/files/temp/a.txt
//                .addResourceLocations(String.format("file:%s/", appConfig.getFiles().getDirectory()))
//        ;
//    }
//
////    /**
////     * 注册过滤器
////     * <pre>
////     * 添加自定义过滤器：设置链路追踪，在日志打印和响应头中追加该标记
////     * 警告：多线程时需要特殊处理
////     * final Map<String, String> mdc = MDC.getCopyOfContextMap(); // 复制主线程 ThreadLocal
////     * new Thread(() -> {
////     *     try {
////     *         MDC.setContextMap(mdc); // 设置子线程 ThreadLocal
////     *         // 子线程代码
////     *     } finally {
////     *         MDC.clear(); // 清除子线程 ThreadLocal
////     *     }
////     * }).start();
////     *
////     * @return FilterRegistrationBean
////     */
////    @Order(0)
////    @Bean
////    public FilterRegistrationBean<Filter> requestIdFilter() {
////        final FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
////        bean.setOrder(0);
////        bean.setFilter(new RequestIdFilter());
////        bean.addUrlPatterns("/*");
////        return bean;
////    }
//
//    /**
//     * <pre>
//     * // http 查询参数构造 final String jsonText = "{\"key\": \"value\", \"number\": 1, \"date\": \"2020-01-01\", \"datetime\": \"2020-01-01 01:01:01\", \"rangeInt\": {\"min\": 1, \"max\": 100}, \"rangeDouble\": {\"min\": \"1.1\", \"max\": \"100.1\"}, \"dateRange\": {\"begin\": \"2020-01-01\", \"end\": \"2020-12-01\"}, \"ids\": [1, 2, 3, 4],, \"names\": [\"a\",\"b\",\"c\",\"d\"], \"orderBy\": [{\"name\": \"id\", \"direction\": \"DESC\"}, {\"name\": \"updateTime\", \"direction\": \"DESC\"}]}";
//     * final JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(queryParams));
//     * if (!jsonObject.isEmpty()) {
//     *     queryString = jsonObject.keySet().stream()
//     *             .map((key) -> {
//     *                 final Object value = jsonObject.get(key);
//     *                 if (value instanceof JSONArray) {
//     *                     JSONArray arr = (JSONArray) value;
//     *                     if (arr.isEmpty()) {
//     *                         return null;
//     *                     }
//     *                     if (arr.get(0) instanceof JSONObject) {
//     *                         return String.format("%s=%s", key, JSON.toJSONString(value));
//     *                     }
//     *                     return String.format("%s=%s", key, arr.stream().map(Objects::toString).collect(Collectors.joining(",")));
//     *                 } else if (value instanceof JSONObject) {
//     *                     if (((JSONObject) value).isEmpty()) {
//     *                         return null;
//     *                     }
//     *                     return String.format("%s=%s", key, JSON.toJSONString(value));
//     *                 } else {
//     *                     return String.format("%s=%s", key, value.toString());
//     *                 }
//     *             })
//     *             .filter(Objects::nonNull)
//     *             .collect(Collectors.joining("&"));
//     *     if (StringUtils.isNotBlank(queryString)) {
//     *         queryString = "?".concat(queryString);
//     *     }
//     * }
//     * <pre/>
//     */
//    @Override
//    public void addFormatters(FormatterRegistry registry) {
////        registry.addFormatter(new VarietyFormatter()); // 而VarietyFormatter可以自动转换我们的各种实体，将他们用在表单上
//        registry.addConverter(String.class, Date.class, value -> yyyy_MM_dd_HH_mm_ss_SSS.parseOfNullable(value).map(Dates::date).orElse(null));
//        registry.addConverter(String.class, Timestamp.class, value -> yyyy_MM_dd_HH_mm_ss_SSS.parseOfNullable(value).map(Dates::timestamp).orElse(null));
//        registry.addConverter(String.class, RangeInt.class, value -> JSON.parseObject(value, RangeInt.class));
//        registry.addConverter(String.class, RangeLong.class, value -> JSON.parseObject(value, RangeLong.class));
//
//        registry.addConverter(String.class, Dates.Range.class, value -> JSON.parseObject(value, Dates.Range.class));
//        registry.addConverter(new Converter<String, Range<BigDecimal>>() {
//            @Override
//            public Range<BigDecimal> convert(final String value) {
//                return JSON.parseObject(value, new TypeReference<Range<BigDecimal>>() {
//                });
//            }
//        });
//        registry.addConverter(new Converter<String, Range<Double>>() {
//            @Override
//            public Range<Double> convert(final String value) {
//                return JSON.parseObject(value, new TypeReference<Range<Double>>() {
//                });
//            }
//        });
//        registry.addConverter(new Converter<String, List<OrderBy>>() {
//            @Override
//            public List<OrderBy> convert(final String value) {
//                return JSON.parseArray(value, OrderBy.class);
//            }
//        });
////        registry.addConverter(new Converter<String, Object[]>() {
////            @Override
////            public Object[] convert(final String dataString) {
////                log.info(dataString);
//////                return yyyy_MM_dd_HH_mm_ss_SSS.parseOfNullable(dateString).map(Dates::timestamp).orElse(null);
////                return null;
////            }
////        });
//    }
//
////    @Bean
////    public RestTemplate apiRestTemplate(final RestTemplateBuilder builder) {
////        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask(); // 解决循环引用问题
////        final FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
////        converter.setSupportedMediaTypes(
////                Arrays.asList(
////                        MediaType.APPLICATION_JSON,
////                        MediaType.APPLICATION_OCTET_STREAM,
////                        MediaType.APPLICATION_FORM_URLENCODED,
////                        MediaType.TEXT_PLAIN
////                )
////        );
////        final FastJsonConfig fastJsonConfig = converter.getFastJsonConfig();
////        fastJsonConfig.setFeatures(Feature.OrderedField);
////        fastJsonConfig.setCharset(UTF_8);
////
////        return builder
////                .setConnectTimeout(Duration.ofSeconds(10))
////                .setReadTimeout(Duration.ofMillis(3))
////                .interceptors((request, body, execution) -> {
////                    final HttpHeaders headers = request.getHeaders();
////                    headers.add("X-ID", RequestIdFilter.get());
////                    return execution.execute(request, body);
////                })
////                .messageConverters(converter)
////                .build();
////    }
//}
